﻿/* 
 * Copyright (c) 2011-12 Andrey Bulygin
 * 
 * This file is part of Interceptor.
 * Interceptor is free software: you can redistribute it and/or modify it under the terms of the GNU 
 * Library General Public License as published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) any later version.
 * 
 * Interceptor is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without 
 * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 
 * the GNU Library General Public License for more details. You should have received a copy of the GNU 
 * Library General Public License along with Interceptor. If not, write to the Free Software Foundation, Inc., 59 
 * Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection.Emit;

namespace Interceptor.Core
{
	internal static class ILGeneratorExtensions
	{
		public static void EmitLdc_I4(this ILGenerator methIL, int value)
		{
			if (value == 0)
				methIL.Emit(OpCodes.Ldc_I4_0);
			else if (value == 1)
				methIL.Emit(OpCodes.Ldc_I4_1);
			else if (value == 2)
				methIL.Emit(OpCodes.Ldc_I4_2);
			else if (value == 3)
				methIL.Emit(OpCodes.Ldc_I4_3);
			else if (value == 4)
				methIL.Emit(OpCodes.Ldc_I4_4);
			else if (value == 5)
				methIL.Emit(OpCodes.Ldc_I4_5);
			else if (value == 6)
				methIL.Emit(OpCodes.Ldc_I4_6);
			else if (value == 7)
				methIL.Emit(OpCodes.Ldc_I4_7);
			else if (value == 8)
				methIL.Emit(OpCodes.Ldc_I4_8);
			else if (value <= sbyte.MaxValue)
				methIL.Emit(OpCodes.Ldc_I4_S, (sbyte)value);
			else
				methIL.Emit(OpCodes.Ldc_I4, value);
		}
		public static void EmitStLoc(this ILGenerator methIL, int index)
		{
			if (index == 0)
				methIL.Emit(OpCodes.Stloc_0);
			else if (index == 1)
				methIL.Emit(OpCodes.Stloc_1);
			else if (index == 2)
				methIL.Emit(OpCodes.Stloc_2);
			else if (index == 3)
				methIL.Emit(OpCodes.Stloc_3);
			else if (index <= sbyte.MaxValue)
				methIL.Emit(OpCodes.Stloc_S, (sbyte)index);
			else
				methIL.Emit(OpCodes.Stloc, index);
		}
		public static void EmitLdLoc(this ILGenerator methIL, int index)
		{
			if (index == 0)
				methIL.Emit(OpCodes.Ldloc_0);
			else if (index == 1)
				methIL.Emit(OpCodes.Ldloc_1);
			else if (index == 2)
				methIL.Emit(OpCodes.Ldloc_2);
			else if (index == 3)
				methIL.Emit(OpCodes.Ldloc_3);
			else if (index <= sbyte.MaxValue)
				methIL.Emit(OpCodes.Ldloc_S, (sbyte)index);
			else
				methIL.Emit(OpCodes.Ldloc, index);
		}
		public static void EmitLdarg(this ILGenerator methIL, short index)
		{
			switch (index)
			{
				case 0: methIL.Emit(OpCodes.Ldarg_0); break;
				case 1: methIL.Emit(OpCodes.Ldarg_1); break;
				case 2: methIL.Emit(OpCodes.Ldarg_2); break;
				case 3: methIL.Emit(OpCodes.Ldarg_3); break;
				default: 
					if (index<=sbyte.MaxValue)
						methIL.Emit(OpCodes.Ldarg_S, (sbyte)index);
					else
						methIL.Emit(OpCodes.Ldarg, index);
					break;
			}
		}

		public static void EmitLdInd(this ILGenerator methIL, Type type)
		{
			if (!type.IsValueType)
			{
				methIL.Emit(OpCodes.Ldind_Ref);
			}
			else
			{
				if (type == typeof(byte))
					methIL.Emit(OpCodes.Ldind_U1);
				else if (type == typeof(sbyte))
					methIL.Emit(OpCodes.Ldind_I1);
				else if (type == typeof(short))
					methIL.Emit(OpCodes.Ldind_I2);
				else if (type == typeof(ushort))
					methIL.Emit(OpCodes.Ldind_U2);
				else if (type == typeof(int))
					methIL.Emit(OpCodes.Ldind_I4);
				else if (type == typeof(uint))
					methIL.Emit(OpCodes.Ldind_U4);
				else if (type == typeof(long))
					methIL.Emit(OpCodes.Ldind_I8);
				else if (type == typeof(ulong))
					methIL.Emit(OpCodes.Ldind_I8);
				else if (type == typeof(float))
					methIL.Emit(OpCodes.Ldind_R4);
				else if (type == typeof(double))
					methIL.Emit(OpCodes.Ldind_R8);
				else 
					methIL.Emit(OpCodes.Ldobj, type);
			}
		}
		public static void EmitStInd(this ILGenerator methIL, Type type)
		{
			if (!type.IsValueType)
			{
				methIL.Emit(OpCodes.Stind_Ref);
			}
			else
			{
				if (type == typeof(byte))
					methIL.Emit(OpCodes.Stind_I1);
				else if (type == typeof(sbyte))
					methIL.Emit(OpCodes.Stind_I1);
				else if (type == typeof(short))
					methIL.Emit(OpCodes.Stind_I2);
				else if (type == typeof(ushort))
					methIL.Emit(OpCodes.Stind_I2);
				else if (type == typeof(int))
					methIL.Emit(OpCodes.Stind_I4);
				else if (type == typeof(uint))
					methIL.Emit(OpCodes.Stind_I4);
				else if (type == typeof(long))
					methIL.Emit(OpCodes.Stind_I8);
				else if (type == typeof(ulong))
					methIL.Emit(OpCodes.Stind_I8);
				else if (type == typeof(float))
					methIL.Emit(OpCodes.Stind_R4);
				else if (type == typeof(double))
					methIL.Emit(OpCodes.Stind_R8);
				else
					methIL.Emit(OpCodes.Stobj, type);
			}
		}
	}
}
